package com.haiya.application.command.impl;

import com.haiya.application.command.CargoCmdService;
import com.haiya.application.command.cmd.CargoBookCommand;
import com.haiya.domain.aggregate.cargo.Cargo;
import com.haiya.domain.aggregate.cargo.CargoBookDomainEvent;
import com.haiya.domain.aggregate.cargo.CargoRepository;
import com.haiya.domain.aggregate.cargo.valueobject.DeliverySpecification;
import com.haiya.domain.aggregate.cargo.valueobject.EnterpriseSegment;
import com.haiya.domain.service.CargoDomainService;
import com.haiya.infrastructure.rpc.salessystem.SalersService;
import com.haiya.shared.DomainEventPublisher;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

/**
 * @author qiaoguoqiang
 */
@Service
public class CargoCmdServiceImpl implements CargoCmdService {
    @Autowired
    private CargoDomainService cargoDomainService;

    @Autowired
    private CargoRepository cargoRepository;

    @Autowired
    private SalersService salersService;

    @Autowired
    DomainEventPublisher domainEventPublisher;
    /**
     * 1. 创建预定货物
     * 2. 流程编排
     * 3. 保存Cargo对象
     * 4. 发布业务领域事件
     * @param cargoBookCommand
     */
    @Override
    public void bookCargo(CargoBookCommand cargoBookCommand) {
        /**
         * 1. 创建预定货物
         */
        DeliverySpecification delivery = new DeliverySpecification(
                cargoBookCommand.getOriginLocationCode(),
                cargoBookCommand.getDestinationLocationCode());

        Cargo cargo = Cargo.newCargo(CargoDomainService.nextCargoId(),
                cargoBookCommand.getSenderPhone(),
                cargoBookCommand.getDescription(),
                delivery);

        /**
         * 2. 流程编排
         *  - 根据客户手机查询预订货物的数量sizeByCustomer
         *  - 调用远程服务(销售服务)获取企业货物所属分类
         *  - 然后检查这种类型货物所能接受的最大预定数量，这里模拟20
         *  - 如果不能接收，则抛出异常
         */
        int size = cargoRepository.sizeByCustomer(cargoBookCommand.getSenderPhone());
        EnterpriseSegment enterpriseSegment = salersService.deriveEnterpriseSegment(cargo);
        int sizeCargo = cargoRepository.sizeByEnterpriseSegment(enterpriseSegment);

        if (!cargoDomainService.mayAccept(size, sizeCargo,
                cargo)) { throw new IllegalArgumentException(
                cargoBookCommand.getSenderPhone() + " cannot book cargo, exceed the limit: "
                        + CargoDomainService.MAX_CARGO_LIMIT); }

        // saveCargo
        cargoRepository.save(cargo);

        // post domain event
        domainEventPublisher.publish(new CargoBookDomainEvent(cargo));
    }
}
